package com.authine.cloudpivot.ext.applicationservice.base;

import com.alibaba.cola.dto.RequestContext;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.Assert;
import com.alibaba.cola.exception.BizException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.ext.constants.AppConst;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.dto.*;
import com.authine.cloudpivot.ext.enums.CustomerOrderStatusEnum;
import com.authine.cloudpivot.ext.enums.OrderGoodsStatusV1Enum;
import com.authine.cloudpivot.ext.enums.commoditymaterials.DeliverNoticeEnum;
import com.authine.cloudpivot.ext.enums.commoditymaterials.MaterialNoticeEnum;
import com.authine.cloudpivot.ext.enums.order.*;
import com.authine.cloudpivot.ext.utils.*;
import com.authine.cloudpivot.ext.utils.system.SessionUser;
import com.authine.hermes.app.launcher.org.Department;
import com.authine.hermes.app.launcher.org.User;
import com.authine.hermes.app.launcher.service.ApplicationService;
import com.authine.mvp.app.launcher.common.TableHelper;
import com.authine.mvp.app.launcher.domain.AttachmentFormat;
import com.authine.mvp.app.launcher.domain.SelectorFormat;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.authine.mvp.app.launcher.dto.bo.response.BO;
import com.authine.mvp.app.launcher.gateway.bo.BOValidatedAndFormatService;
import com.authine.mvp.app.launcher.utils.JsonParseObject;
import com.authine.mvp.app.org.dto.domainmodel.UnitType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class ApplicationBaseService extends ApplicationService {
    private final NamedParameterJdbcTemplate jdbcTemplate = ApplicationContextUtils.getBean(NamedParameterJdbcTemplate.class);
    private final TableHelper tableHelper = ApplicationContextUtils.getBean(TableHelper.class);
    private BOValidatedAndFormatService bOValidatedAndFormatService = ApplicationContextUtils.getBean(BOValidatedAndFormatService.class);

    /**
     * ----------------------------------------------------DB通用执行sql------start---------------------------------------------
     */

    /**
     * 获取某个表的数据通过主键id
     *
     * @param id
     * @param schemaCode
     * @return
     */
    public Map<String, Object> selectModelById(String id, String schemaCode) {
        return selectModelById(id, null, schemaCode);
    }

    /**
     * 获取某个表的数据通过主键id，可跨数据库
     *
     * @param id
     * @param appCode
     * @param schemaCode
     * @return
     */
    public Map<String, Object> selectModelById(String id, String appCode, String schemaCode) {
        String tableName = getTableName(appCode, schemaCode);
        log.info("------------------------通过多个参数查询" + tableName + "表 Param：{}------------------------", id);
        if (StringUtils.isBlank(id) || StringUtils.isBlank(tableName)) {
            return null;
        }
        StringBuilder listSql = new StringBuilder();
        listSql.append("select * from " + tableName + " where deleted = '0' and id ='" + id + "'");
        log.info("------------------------通过多个参数查询" + tableName + "表 SQL：{}------------------------", listSql);
        List<Map<String, Object>> result = jdbcTemplate.queryForList(listSql.toString(), new HashMap<>());
        if (CollectionUtils.isEmpty(result)) {
            return null;
        } else {
            return result.get(0);
        }
    }

    /**
     * 获取某个表的数据通过主键id，可跨数据库
     *
     * @param ids
     * @return
     */
    public List<Map<String, Object>> selectModelByIn(Map<String, List<String>> ids, String tableName) {
        log.info("------------------------通过多个参数查询" + tableName + "表 Param：{}------------------------", ids);
        if (CollectionUtils.isEmpty(ids) || StringUtils.isBlank(tableName)) {
            return null;
        }
        StringBuilder listSql = new StringBuilder();
        StringBuilder sql = new StringBuilder();
        for (String key : ids.keySet()) {
            String idInSql = ids.get(key).stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", "));
            listSql.append(" and " + key + " in (" + idInSql + ")");
        }

        sql.append("select * from " + tableName + " where deleted = '0' " + listSql);
        log.info("------------------------通过多个参数查询" + tableName + "表 SQL：{}------------------------", sql);
        List<Map<String, Object>> result = jdbcTemplate.queryForList(sql.toString(), new HashMap<>());
        if (CollectionUtils.isEmpty(result)) {
            return null;
        } else {
            return result;
        }
    }

    /**
     * 获取某个表的数据通过多个参数，可跨数据库
     *
     * @param appCode
     * @param schemaCode
     * @return
     */
    public List<Map<String, Object>> selectModelByMaps(List<Map<String, Object>> paramList, String appCode, String schemaCode) {
        String tableName = getTableName(appCode, schemaCode);
        log.info("------------------------通过多个参数查询" + tableName + "表 Param：{}------------------------", paramList);
        if (CollectionUtils.isEmpty(paramList)) {
            return null;
        }
        String sql = "";
        for (Map<String, Object> map : paramList) {
            for (String key : map.keySet()) {
                sql += " and " + key + " ='" + map.get(key) + "'";
            }
        }
        StringBuilder listSql = new StringBuilder();
        listSql.append("select * from " + tableName + " where deleted = '0' " + sql);
        log.info("------------------------通过多个参数查询" + tableName + "表 SQL：{}------------------------", listSql);
        List<Map<String, Object>> result = jdbcTemplate.queryForList(listSql.toString(), new HashMap<>());
        return result;
    }

    /**
     * 获取某个表的数据通过参数，可多参数
     *
     * @return
     */
    public List<Map<String, Object>> selectModelByMaps(List<Map<String, Object>> paramList, String schemaCode) {
        return selectModelByMaps(paramList, null, schemaCode);
    }

    /**
     * 获取某个表的数据通过参数，可多参数
     *
     * @return
     */
    public List<Map<String, Object>> selectModelByMaps(Map<String, Object> paramMap, String appCode, String schemaCode) {
        return selectModelByMaps(Collections.singletonList(paramMap), appCode, schemaCode);
    }

    /**
     * 获取某个表的数据通过参数，可多参数
     *
     * @param schemaCode
     * @return
     */
    public List<Map<String, Object>> selectModelByMaps(Map<String, Object> paramMap, String schemaCode) {
        return selectModelByMaps(Collections.singletonList(paramMap), null, schemaCode);
    }

    /**
     * 获取当前登录人部门信息
     *
     * @return
     */
    public Map<String, Object> getCurrentDept() {
        StringBuilder listSql = new StringBuilder();
        listSql.append("select d.* from " + AppConst.APP_COMMONSERVICE + ".h_org_department d " +
                "inner JOIN " + AppConst.APP_COMMONSERVICE + ".h_org_dept_user du on d.id = du.deptId " +
                "inner join " + AppConst.APP_COMMONSERVICE + ".h_org_user u on u.id = du.userId " +
                "where u.userBaseId ='" + RequestContext.getLoginId() + "'");
        log.info("------------------------通过当前登录人用户id:{}查询用户所在部门 SQL：{}------------------------", RequestContext.getLoginId(), listSql);
        List<Map<String, Object>> result = jdbcTemplate.queryForList(listSql.toString(), new HashMap<>());
        if (CollectionUtils.isEmpty(result)) {
            return null;
        } else {
            return result.get(0);
        }
    }

    /**
     * 获取应用表名(可获取其他应用表名)
     *
     * @param appCode
     * @param schemaCode
     * @return
     */
    public String getTableName(String appCode, String schemaCode) {
        if (StringUtils.isBlank(appCode)) {
            return getTableName(schemaCode);
        }
        return String.format("%s.i_%s_%s", appCode.toLowerCase(), appCode.toLowerCase(), schemaCode.toLowerCase());
    }

    /**
     * 获取表名称
     *
     * @param schemaCode
     * @return
     */
    public String getTableName(String schemaCode) {
        return tableHelper.getTableName(schemaCode);
    }

    /**
     * 获取当前登录人角色
     */
    public List<Map<String, Object>> getCurrentUserRole() {
        String sql = "select d.* from " + AppConst.APP_COMMONSERVICE + ".h_org_role d " +
                "inner JOIN " + AppConst.APP_COMMONSERVICE + ".h_org_role_user du on d.id = du.roleId " +
                "inner join " + AppConst.APP_COMMONSERVICE + ".h_org_user u on u.id = du.unitId " +
                "where u.userBaseId = '" + RequestContext.getLoginId() + "'";
        List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, new HashMap<>());
        if (CollectionUtils.isEmpty(result)) {
            return null;
        } else {
            return result;
        }
    }

    /**
     * 通过userBaseId获取选人控件值
     *
     * @param id
     * @return
     */
    public SelectorFormat getSelectorFormat(String id, UnitType unitType) {
        if (StringUtils.isBlank(id)) {
            id = RequestContext.getCorpLoginId();
        }
        SelectorFormat senderSF = new SelectorFormat();
        User sender = this.orgService.getUserByUserId(id).getData();
        //部门
        if (unitType.getIndex() == 1) {
            senderSF.setId(sender.getDetailInfo().getDepartmentId());
            senderSF.setName(sender.getDetailInfo().getMainDepartmentName());
            senderSF.setType(unitType.getIndex());
        }
        //角色
        if (unitType.getIndex() == 2) {
            senderSF.setId(sender.getDetailInfo().getRoleIds().get(0));
            senderSF.setName(sender.getDetailInfo().getRoleName());
            senderSF.setType(unitType.getIndex());
        }
        //用户
        if (unitType.getIndex() == 3) {
            senderSF.setId(sender.getDetailInfo().getId());
            senderSF.setName(sender.getDetailInfo().getName());
            senderSF.setType(unitType.getIndex());
        }
        return senderSF;
    }

    /**
     * 通过userBaseId获取选人控件值
     *
     * @return
     */
    public SelectorFormat getSelectorFormat() {
        SelectorFormat senderSF = new SelectorFormat();
        senderSF.setId(RequestContext.getLoginId());
        senderSF.setName(RequestContext.getLoginRealName());
        senderSF.setType(3);
        return senderSF;
    }

    /**
     * 获取退货订单商品表通过订单商品id
     */
    public List<Map<String, Object>> getGoodsReturnsByOrderGoodsId(Collection<String> orderCustomerGoodsId, Collection<String> orderVendorGoodsId) {
        String orderGoodsReturnsDB = getTableName(ModelConst.T_ORDER_GOODS_RETURNS);
        if (CollectionUtils.isEmpty(orderCustomerGoodsId) && CollectionUtils.isEmpty(orderVendorGoodsId)) {
            return null;
        }
        StringBuilder orderGoodsReturnsSql = new StringBuilder();
        orderGoodsReturnsSql.append("select * from " + orderGoodsReturnsDB + " where deleted = '0' ");
        if (!CollectionUtils.isEmpty(orderCustomerGoodsId)) {
            String orderCustomerGoodsIdInSql = " and order_customer_goods_id in (" + orderCustomerGoodsId.stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", ")) + ")";
            orderGoodsReturnsSql.append(orderCustomerGoodsIdInSql);
        }
        if (!CollectionUtils.isEmpty(orderVendorGoodsId)) {
            String orderVendorGoodsIdIdInSql = " and order_vendor_goods_id in (" + orderVendorGoodsId.stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", ")) + ")";
            orderGoodsReturnsSql.append(orderVendorGoodsIdIdInSql);
        }
        return jdbcTemplate.queryForList(orderGoodsReturnsSql.toString(), new HashMap<>());
    }

    /**
     * 获取供应商订单商品表通过订单商品id
     */
    public List<Map<String, Object>> getOrderVendorGoodsByGoodsId(Collection<String> orderGoodsId, Collection<String> vendorOrgIds) {
        if (CollectionUtils.isEmpty(orderGoodsId)) {
            return null;
        }
        StringBuilder orderVendorGoodsSql = new StringBuilder();
        if (!CollectionUtils.isEmpty(vendorOrgIds)) {
            String orderVendorGoodsIdIdInSql = " and vendor_organization_id in (" + vendorOrgIds.stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", ")) + ")";
            orderVendorGoodsSql.append(orderVendorGoodsIdIdInSql);
        }
        String orderVendorGoodsDB = getTableName(ModelConst.T_ORDER_VENDOR_GOODS);
        String orderVendorGoodsIdInSql = orderGoodsId.stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", "));
        String sql = "select * from " + orderVendorGoodsDB + " where deleted = '0' and id in (" + orderVendorGoodsIdInSql + ")";
        List<Map<String, Object>> orderVendorGoodsList = jdbcTemplate.queryForList(sql, new HashMap<>());
        return orderVendorGoodsList;
    }

    /**
     * 获取客户订单商品表通过订单商品id
     */
    public List<Map<String, Object>> getOrderCustomerGoodsByGoodsId(Collection<String> orderGoodsId) {
        if (CollectionUtils.isEmpty(orderGoodsId)) {
            return null;
        }
        String orderCustomerGoodsDB = getTableName(ModelConst.T_ORDER_CUSTOMER_GOODS);
        String orderCustomerGoodsIdInSql = orderGoodsId.stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", "));
        String sql = "select * from " + orderCustomerGoodsDB + " where deleted = '0' and id in (" + orderCustomerGoodsIdInSql + ")";
        List<Map<String, Object>> orderCustomerGoodsList = jdbcTemplate.queryForList(sql, new HashMap<>());
        return orderCustomerGoodsList;
    }

    /**
     * 获取订单商品收货表通过客户订单商品id或供应商订单商品id
     */
    public List<Map<String, Object>> getOrderGoodsAcceptByGoodsId(Collection<String> orderCustomerGoodsId, Collection<String> orderVendorGoodsId) {
        if (CollectionUtils.isEmpty(orderCustomerGoodsId) && CollectionUtils.isEmpty(orderVendorGoodsId)) {
            return null;
        }
        String orderGoodsAcceptDB = getTableName(ModelConst.T_ORDER_GOODS_ACCEPT);
        StringBuilder orderGoodsAcceptSql = new StringBuilder();
        orderGoodsAcceptSql.append("select * from " + orderGoodsAcceptDB + " where deleted = '0' ");
        if (!CollectionUtils.isEmpty(orderCustomerGoodsId)) {
            String orderCustomerGoodsIdInSql = " and order_customer_goods_id in (" + orderCustomerGoodsId.stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", ")) + ")";
            orderGoodsAcceptSql.append(orderCustomerGoodsIdInSql);
        }
        if (!CollectionUtils.isEmpty(orderVendorGoodsId)) {
            String orderVendorGoodsIdIdInSql = " and order_vendor_goods_id in (" + orderVendorGoodsId.stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", ")) + ")";
            orderGoodsAcceptSql.append(orderVendorGoodsIdIdInSql);
        }
        return jdbcTemplate.queryForList(orderGoodsAcceptSql.toString(), new HashMap<>());
    }

    /**
     * 获取订单商品收货表通过客户订单商品id或供应商订单商品id
     */
    public List<Map<String, Object>> getOrderGoodsTraceByGoodsId(String orderCustomerGoodsId, String orderVendorGoodsId) {
        if (StringUtils.isBlank(orderCustomerGoodsId) && StringUtils.isBlank(orderVendorGoodsId)) {
            return null;
        }
        String orderTraceDB = getTableName(ModelConst.T_ORDER_TRACE);
        StringBuilder orderTraceSql = new StringBuilder();
        orderTraceSql.append("select * from " + orderTraceDB + " where deleted = '0' ");
        if (!StringUtils.isBlank(orderCustomerGoodsId)) {
            String orderCustomerGoodsIdInSql = " and order_customer_goods_id = '" + orderCustomerGoodsId + "'";
            orderTraceSql.append(orderCustomerGoodsIdInSql);
        }
        if (!StringUtils.isBlank(orderVendorGoodsId)) {
            String orderVendorGoodsIdIdInSql = " and order_vendor_goods_id = '" + orderVendorGoodsId + "'";
            orderTraceSql.append(orderVendorGoodsIdIdInSql);
        }
        return jdbcTemplate.queryForList(orderTraceSql.toString(), new HashMap<>());
    }

    /**
     * 获取个人中心地址
     */
    public List<Map<String, Object>> getAddress(String memberId, boolean defaultOnly, String id) {
        String tableName = getTableName(AppConst.PERSONAL_CENTER, ModelConst.T_MEMBER_DELIVER_ADDRESS);
        StringBuilder sql = new StringBuilder();
        sql.append("select * from " + tableName + " where deleted ='0'");
        if (null != memberId) {
            sql.append(" and member_id->'$.id' = '" + memberId + "'");
        } else {
            sql.append(" and member_id->'$.id' = '" + RequestContext.getCorpLoginId() + "'");
        }
        if (defaultOnly) {
            sql.append(" and default_address = '1'");
        }
        if (StringUtils.isNotBlank(id)) {
            sql.append(" and id = '" + id + "'");
        }
        log.info("------------------------查询 SQL：{}------------------------", sql);
        List<Map<String, Object>> result = jdbcTemplate.queryForList(sql.toString(), new HashMap<>());
        if (CollectionUtils.isEmpty(result)) {
            return null;
        } else {
            return result;
        }
    }

    /**
     * 获取个人会员银行信息表
     */
    public List<Map<String, Object>> getBankAccount(String memberId, boolean defaultOnly, String id) {
        String tableName = getTableName(AppConst.PERSONAL_CENTER, ModelConst.T_MEMBER_BANK_ACCOUNT);
        StringBuilder sql = new StringBuilder();
        sql.append("select * from " + tableName + " where deleted ='0'");
        if (null != memberId) {
            sql.append(" and member_id->'$.id' = '" + memberId + "'");
        } else {
            sql.append(" and member_id->'$.id' = '" + RequestContext.getCorpLoginId() + "'");
        }
        if (defaultOnly) {
            sql.append(" and default_bank_account = '1'");
        }
        if (StringUtils.isNotBlank(id)) {
            sql.append(" and id = '" + id + "'");
        }
        log.info("------------------------查询 SQL：{}------------------------", sql);
        List<Map<String, Object>> result = jdbcTemplate.queryForList(sql.toString(), new HashMap<>());
        if (CollectionUtils.isEmpty(result)) {
            return null;
        } else {
            return result;
        }
    }

    /**
     * 获库存使用单据相关物料表通过id集合
     */
    public List<Map<String, Object>> getStockBillMaterialByIds(Collection<String> stockBillMaterialIds) {
        if (CollectionUtils.isEmpty(stockBillMaterialIds)) {
            return null;
        }
        String stockBillMaterialDB = getTableName(ModelConst.T_STOCK_BILL_MATERIAL);
        String stockBillMaterialInSql = stockBillMaterialIds.stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", "));
        String sql = "select * from " + stockBillMaterialDB + " where deleted = '0' and id in (" + stockBillMaterialInSql + ")";
        List<Map<String, Object>> stockBillMaterialList = jdbcTemplate.queryForList(sql, new HashMap<>());
        return stockBillMaterialList;
    }

    /**
     * @param goodsId
     * @return
     */
    public Map<String, Object> getInquiryGoodsByGoodsId(String goodsId) {
        if (StringUtils.isBlank(goodsId)) {
            return null;
        }
        //最大库存量
        StringBuilder listSql = new StringBuilder();
        String goodsPurchaseTableName = getTableName(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODS_PURCHASE);
        String quotationGoodsTableName = getTableName(AppConst.SOURCING_CENTER, ModelConst.T_QUOTATION_GOODS);
        String inquiryGoodsTableName = getTableName(AppConst.SOURCING_CENTER, ModelConst.T_INQUIRY_GOODS);
        listSql.append("select ig.* from " + goodsPurchaseTableName + " pg\n" +
                " inner join " + quotationGoodsTableName + " qg on pg.quotation_goods_id = qg.id\n" +
                " inner join " + inquiryGoodsTableName + " ig on qg.inquiry_goods_id = ig.id\n" +
                " where pg.id = '" + goodsId + "' and pg.deleted = '0' and qg.deleted ='0' and ig.deleted ='0'");
        List<Map<String, Object>> results = jdbcTemplate.queryForList(listSql.toString(), new HashMap<>());
        if (CollectionUtils.isEmpty(results)) {
            return null;
        } else {
            return results.get(0);
        }
    }

    /**
     * @param goodsId
     * @return
     */
    public Map<String, Object> getQuotationGoodsByGoodsId(String goodsId) {
        if (StringUtils.isBlank(goodsId)) {
            return null;
        }
        //最大库存量
        StringBuilder listSql = new StringBuilder();
        String goodsPurchaseTableName = getTableName(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODS_PURCHASE);
        String quotationGoodsTableName = getTableName(AppConst.SOURCING_CENTER, ModelConst.T_QUOTATION_GOODS);
        listSql.append("select qg.* from " + goodsPurchaseTableName + " pg\n" +
                " inner join " + quotationGoodsTableName + " qg on pg.quotation_goods_id = qg.id\n" +
                " where pg.id = '" + goodsId + "' and pg.deleted = '0' and qg.deleted ='0' ");
        List<Map<String, Object>> results = jdbcTemplate.queryForList(listSql.toString(), new HashMap<>());
        if (CollectionUtils.isEmpty(results)) {
            return null;
        } else {
            return results.get(0);
        }
    }

    /**
     * 获取数据字典
     *
     * @param code
     * @param type
     * @return
     */
    /*public List<Map<String, Object>> getDictionaryItem(String code, DictionaryType type, String itemCode) {
        //默认查询简单键值结构
        if (null == type) {
            type = DictionaryType.KEYVALUE;
        }
        StringBuilder sql = new StringBuilder();
        sql.append("select di.* from " + AppConst.APP_METADATA + "." + ModelConst.DICTIONARY + " d " +
                " inner join " + AppConst.APP_METADATA + "." + ModelConst.DICTIONARY_ITEM + " di on d.id = di.dict_id " +
                " where d.type='" + type.getCode() + "' and d.deleted='0' and di.deleted='0'");
        if (StringUtils.isNotBlank(code)) {
            sql.append(" and d.code = '" + code + "'");
        }
        if (StringUtils.isNotBlank(itemCode)) {
            sql.append(" and di.code = '" + itemCode + "'");
        }
        List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sql.toString(), new HashMap<>());
        return resultList;
    }
*/
    /**----------------------------------------------------DB通用执行sql------end---------------------------------------------*/


    /**
     * ----------------------------------------------------订单数量次数相关计算------start---------------------------------------------
     */
    //已发次数
    public Integer getDeliverCount(String orderCustomerGoodsId, String orderVendorGoodsId) {
        List<Map<String, Object>> orderGoodsTraceGoodsId = getOrderGoodsTraceByGoodsId(orderCustomerGoodsId, orderVendorGoodsId);
        return null != orderGoodsTraceGoodsId && !orderGoodsTraceGoodsId.isEmpty() ? orderGoodsTraceGoodsId.size() : 0;
    }

    //已发数量
    public BigDecimal getDeliveredNum(String orderCustomerGoodsId, String orderVendorGoodsId) {
        List<Map<String, Object>> transportByOrderGoodsId = getOrderGoodsTraceByGoodsId(orderCustomerGoodsId, orderVendorGoodsId);
        BigDecimal deliveredNum = BigDecimal.ZERO;
        for (Map<String, Object> item : transportByOrderGoodsId) {
            if (null != item.get("quantity") && item.get("type").equals(TraceTypeEnum.ShippingLogistics))
                deliveredNum = BigDecimalUtils.add(deliveredNum, BigDecimalUtils.isNull(item.get("quantity")));
        }
        return deliveredNum;
    }

    //已收次数
    public Integer getReceiveCount(String orderCustomerGoodsId, String orderVendorGoodsId) {
        List<Map<String, Object>> receivedByOrderGoodsId = getOrderGoodsAcceptByGoodsId(Collections.singletonList(orderCustomerGoodsId), Collections.singletonList(orderVendorGoodsId));
        return null != receivedByOrderGoodsId && !receivedByOrderGoodsId.isEmpty() ? receivedByOrderGoodsId.size() : 0;
    }

    //已收数量
    public BigDecimal getReceivedNum(String orderCustomerGoodsId, String orderVendorGoodsId) {
        List<Map<String, Object>> receivedByOrderGoodsId = getOrderGoodsAcceptByGoodsId(Collections.singletonList(orderCustomerGoodsId), Collections.singletonList(orderVendorGoodsId));
        BigDecimal recevicedNum = BigDecimal.ZERO;
        for (Map<String, Object> item : receivedByOrderGoodsId) {
            if (null != item.get("quantity_received"))
                recevicedNum = BigDecimalUtils.add(recevicedNum, BigDecimalUtils.isNull(item.get("quantity_received")));
        }
        return recevicedNum;
    }

    //已退次数
    public Integer getRefundCount(String orderCustomerGoodsId, String orderVendorGoodsId) {
        Collection<String> orderCustomerGoodsIds = StringUtils.isBlank(orderCustomerGoodsId) ? null : Collections.singleton(orderCustomerGoodsId);
        Collection<String> orderVendorGoodsIds = StringUtils.isBlank(orderVendorGoodsId) ? null : Collections.singleton(orderVendorGoodsId);
        List<Map<String, Object>> refundByOrderGoodsId = getGoodsReturnsByOrderGoodsId(orderCustomerGoodsIds, orderVendorGoodsIds);
        return null != refundByOrderGoodsId && !refundByOrderGoodsId.isEmpty() ? refundByOrderGoodsId.size() : 0;
    }

    //已退数量
    public BigDecimal getRefundedNum(String orderCustomerGoodsId, String orderVendorGoodsId) {
        Collection<String> orderCustomerGoodsIds = StringUtils.isBlank(orderCustomerGoodsId) ? null : Collections.singleton(orderCustomerGoodsId);
        Collection<String> orderVendorGoodsIds = StringUtils.isBlank(orderVendorGoodsId) ? null : Collections.singleton(orderVendorGoodsId);
        List<Map<String, Object>> refundByOrderGoodsId = getGoodsReturnsByOrderGoodsId(orderCustomerGoodsIds, orderVendorGoodsIds);
        BigDecimal refundedNum = BigDecimal.ZERO;
        for (Map<String, Object> item : refundByOrderGoodsId) {
            if (null != item.get("quantity")&&null!= item.get("order_goods_returns_status")&& OrderGoodsReturnsStatusEnum.getNormalStatus().contains(item.get("order_goods_returns_status")))
                refundedNum = BigDecimalUtils.add(refundedNum, BigDecimalUtils.isNull(item.get("quantity")));
        }
        return refundedNum;
    }


    //可收数量（已发数量-已收数量-已退货数量+退的收货的数量）
    @Deprecated
    public BigDecimal getEnableNum(String orderCustomerGoodsId, String orderVendorGoodsId, BigDecimal returnedNum, BigDecimal returnReceivedNum) {
        if (null == orderCustomerGoodsId && null == orderVendorGoodsId) return BigDecimal.ZERO;
        return BigDecimalUtils.add(BigDecimalUtils.sub(BigDecimalUtils.sub(getDeliveredNum(orderCustomerGoodsId, orderVendorGoodsId),
                getReceivedNum(orderCustomerGoodsId, orderVendorGoodsId)), returnedNum), returnReceivedNum);
    }

    //可收数量 = 订单总数（t_order_customer_goods.quantity）-退未发数量（t_order_customer_goods.quantity_return_not_shipped）-已收数量（t_order_customer_goods.quantity_received）
    public BigDecimal getEnableNum(String orderCustomerGoodsId) {
        if (StringUtils.isBlank(orderCustomerGoodsId)) {
            return BigDecimal.ZERO;
        }
        Map<String, Object> orderCustomerGoods = JdbcTemplateUtils.builder(ModelConst.T_ORDER_CUSTOMER_GOODS)
                .selectField("(quantity-ifnull(quantity_return_not_shipped, 0.0)-ifnull(quantity_received, 0.0)) as enable_num").eq("id", orderCustomerGoodsId).queryForMap();
        return CollectionUtils.isEmpty(orderCustomerGoods)?BigDecimal.ZERO:BigDecimalUtils.isNull(orderCustomerGoods.get("enable_num"));
    }

    //可退数量（总数量-已退数量）
    public BigDecimal getRefundableNum(String orderCustomerGoodsId, String orderVendorGoodsId, BigDecimal num) {
        if (null == orderCustomerGoodsId && null == orderVendorGoodsId) return BigDecimal.ZERO;
        return BigDecimalUtils.sub(num, getRefundedNum(orderCustomerGoodsId, orderVendorGoodsId));
    }

    //可退数量：订单总数（t_order_customer_goods.quantity）-退未发货数量（t_order_customer_goods.quantity_return_not_shipped）-退已发货数量（t_order_customer_goods.quantity_return_shipped）
    public BigDecimal getRefundableNum(String orderCustomerGoodsId) {
        Map<String, Object> orderCustomerGoods = JdbcTemplateUtils.builder(ModelConst.T_ORDER_CUSTOMER_GOODS)
                .selectField("(quantity-ifnull(quantity_return_not_shipped, 0.0)-ifnull(quantity_return_shipped, 0.0)) as refundable_num")
                .eq("id", orderCustomerGoodsId).queryForMap();
        return CollectionUtils.isEmpty(orderCustomerGoods)?BigDecimal.ZERO:BigDecimalUtils.isNull(orderCustomerGoods.get("refundable_num"));
    }

    //可发数量（可退数量-已发数量+已退货数量）
    @Deprecated
    public BigDecimal getDeliverableNum(String orderCustomerGoodsId, String orderVendorGoodsId, BigDecimal returnedNum, BigDecimal num) {
        if (null == orderCustomerGoodsId && null == orderVendorGoodsId) return BigDecimal.ZERO;
        return BigDecimalUtils.add(BigDecimalUtils.sub(getRefundableNum(orderCustomerGoodsId, orderVendorGoodsId, num),
                getDeliveredNum(orderCustomerGoodsId, orderVendorGoodsId)), returnedNum);
    }

    //可发数量 = 订单总数（t_order_vendor_goods.quantity）-退未发货数量（t_order_vendor_goods.quantity_return_not_shipped）-已发货数量（t_order_vendor_goods.quantity_shipped）
    public BigDecimal getDeliverableNum(String orderVendorGoodsId) {
        if (StringUtils.isBlank(orderVendorGoodsId)) {
            return BigDecimal.ZERO;
        }
        Map<String, Object> orderCustomerGoods = JdbcTemplateUtils.builder(ModelConst.T_ORDER_VENDOR_GOODS)
                .selectField("(quantity-ifnull(quantity_return_not_shipped, 0.0)-ifnull(quantity_shipped, 0.0)) as deliverable_num")
                .eq("id", orderVendorGoodsId).queryForMap();
        return CollectionUtils.isEmpty(orderCustomerGoods)?BigDecimal.ZERO:BigDecimalUtils.isNull(orderCustomerGoods.get("deliverable_num"));
    }

    //未发货数量=总数量-已退的-已发货数量+仅退货数量
    public BigDecimal getUndeliveredNum(String orderCustomerGoodsId) {
        if (StringUtils.isBlank(orderCustomerGoodsId)) {
            return BigDecimal.ZERO;
        }
        Map<String, Object> orderCustomerGoods = JdbcTemplateUtils.builder(ModelConst.T_ORDER_CUSTOMER_GOODS)
                .selectField("(quantity-ifnull(quantity_return_not_shipped, 0.0)-ifnull(quantity_return_shipped, 0.0)-ifnull(quantity_shipped, 0.0)+ifnull(returned_num, 0.0)) as undelivered_num")
                .eq("id", orderCustomerGoodsId).queryForMap();
        return CollectionUtils.isEmpty(orderCustomerGoods)?BigDecimal.ZERO:BigDecimalUtils.isNull(orderCustomerGoods.get("undelivered_num"));
    }
    /**----------------------------------------------------订单数量次数相关计算------end---------------------------------------------*/

    /**
     * 订单商品结束后触发修改供应商订单与客户订单状态.
     *
     * @param customerOrderIds 客户订单ID列表
     */
    public void updateStatus(List<String> customerOrderIds) {
        if (CollectionUtils.isEmpty(customerOrderIds)) {
            return;
        }
        String orderCustomerDB = getTableName(ModelConst.T_ORDER_CUSTOMER);
        String orderCustomerInSql = customerOrderIds.stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", "));
        String orderCustomerSql = "select * from " + orderCustomerDB + " where deleted = '0' and id in (" + orderCustomerInSql + ")";
        List<Map<String, Object>> customerOrderList = jdbcTemplate.queryForList(orderCustomerSql, new HashMap<>());

        if (CollectionUtils.isEmpty(customerOrderList)) {
            return;
        }

        List<Map<String, Object>> orderGoodsList = new ArrayList<>();
        for (Map<String, Object> customerOrder : customerOrderList) {
            String orderVendorDB = getTableName(ModelConst.T_ORDER_VENDOR);
            String orderVendorSql = "select * from " + orderVendorDB + " where deleted = '0' and order_customer_id = '" + customerOrder.get("id") + "'";
            List<Map<String, Object>> vendorOrderList = jdbcTemplate.queryForList(orderVendorSql, new HashMap<>());

            if (CollectionUtils.isEmpty(vendorOrderList)) {
                throw new RuntimeException("未查到对应的供应商订单状态");
            }

            String orderCustomerGoodsDB = getTableName(ModelConst.T_ORDER_CUSTOMER_GOODS);
            String orderCustomerGoodsSql = "select * from " + orderCustomerGoodsDB + " where deleted = '0' and order_customer_id = '" + customerOrder.get("id") + "'";
            List<Map<String, Object>> orderCustomerGoodsList = jdbcTemplate.queryForList(orderCustomerGoodsSql, new HashMap<>());

            orderGoodsList.addAll(orderCustomerGoodsList);

            //如果为VMI订单则直接修改为已完成
            if (isVMI((String) customerOrder.get("id"))) {
                customerOrder.put("order_customer_status", CustomerOrderStatusEnum.DONE.name());

                String updateVendorStatusSql = "update " + orderVendorDB + " set status = '" + OrderVendorStatusEnum.Done.name() + "' where order_customer_id= '" + customerOrder.get("id") + "' and deleted ='0'";
                jdbcTemplate.update(updateVendorStatusSql, new HashMap<>());
                continue;
            }

            Set<OrderVendorStatusEnum> vendorOrderStatusList = new HashSet<>();
            boolean isExistNotOver = false;
            //非VMI订单需要根据订单商品状态修改供应商订单
            for (Map<String, Object> vendorOrder : vendorOrderList) {
                //如果供应商订单下的商品存在非【DONE、CLOSED、RETURNED】这三种状态则不修改
//                String orderVendorDB = getTableName(ModelConst.T_ORDER_VENDOR);
                String isExistNotOverSql = "select count (*) from " + orderVendorDB + " where deleted = '0' and id = '" + customerOrder.get("id") + "' and order_vendor_status <> 11 and order_vendor_status<> 12 and order_vendor_status <> 14 ";
                Integer existNotOver = 0;
                try {
                    existNotOver = jdbcTemplate.queryForObject(isExistNotOverSql, new HashMap<>(), Integer.class);
                } catch (DataAccessException e) {
                    e.printStackTrace();
                }

                if (existNotOver != 0) {
                    isExistNotOver = true;
                    continue;
                }

//                VendorOrderStatusEnum vendorOrderStatus = iOrderGoodsRepository.getVendorOrderStatusByOverOrderGoodsStatus(vendorOrder.getId());
//                vendorOrder.setStatus(vendorOrderStatus);

//                iVendorOrderRepository.update(vendorOrder);
//                vendorOrderStatusList.add(vendorOrderStatus);
            }

            if (isExistNotOver) {
                continue;
            }

            //根据供应商订单状态修改客户订单
            if (vendorOrderStatusList.contains(OrderVendorStatusEnum.Done.name())) {
                customerOrder.put("order_customer_status", CustomerOrderStatusEnum.DONE.name());
            } else {
                customerOrder.put("order_customer_status", CustomerOrderStatusEnum.CANCEL.name());
            }
            BoServiceUtils.updateMainBo(ModelConst.T_ORDER_CUSTOMER, customerOrder);
        }
        //修改转采订单状态
//        updateTransferOrderStatus(orderGoodsList);
    }

    /**
     * 是否为VMI订单
     *
     * @param customerOrderId
     * @return
     */
    private boolean isVMI(String customerOrderId) {
        String orderCustomerGoodsDB = getTableName(ModelConst.T_ORDER_CUSTOMER_GOODS);
        String orderCustomerGoodsSql = "select * from " + orderCustomerGoodsDB + " where deleted = '0' and goods_src = 'Vmi' and order_customer_id = '" + customerOrderId + "'";
        List<Map<String, Object>> orderCustomerGoodsList = jdbcTemplate.queryForList(orderCustomerGoodsSql, new HashMap<>());
        if (CollectionUtils.isEmpty(orderCustomerGoodsList)) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 批量发货
     *
     * @param orderGoodsIds 订单商品id
     * @param waybill
     * @param logistics
     * @return
     */
    public Map<String, Object> deliveryGoods(List<String> orderGoodsIds, String waybill, String logistics) {
        Map<String, Object> result = new HashMap<>();
        if (null == orderGoodsIds || orderGoodsIds.isEmpty() || null == waybill || null == logistics) {
            throw new RuntimeException("参数为空");
        }
        //批量发货
//        Long vendorOrderOrgId = iOrdersService.getVendorOrderOrgId(sessionUser.getCurrentOrgID(), orderGoodsIds.get(0));
        List<Map<String, Object>> orderVendorGoods = getOrderVendorGoodsByGoodsId(Collections.singletonList(orderGoodsIds.get(0)), null);
        SingleResponse<Department> deptRes = this.orgService.getDepartment((String) orderVendorGoods.get(0).get("vendor_organization_id"));
        //判断是否为虚拟供应商dept.getData().getExtend1() == true,即为转采采购订单
        if (deptRes.getData().getExtend1().equals("1")) {
//            List<Integer> cloudDeliverGoods = purchaseOrderService.getCloudDeliverGoods(orderGoodsIds);
//            if (!cloudDeliverGoods.isEmpty()) {
//                throw new RuntimeException("商品编号：" + cloudDeliverGoods + "，未创建转采采购订单，无法发货");
//            }
        }

        /**List<TransportEntity> transportList = iOrdersService
         .saveTransport(new TransportEntity(null, null, null, null, logistics, null, null, 0.0), orderGoodsIds, Collections.singletonList(waybill), null, false, null);
         if (!org.apache.commons.collections4.CollectionUtils.isEmpty(transportList)) {
         result.setTraceIds(transportList.stream().map(BaseEntity::getId).collect(Collectors.toList()));
         }
         result.setOrderGoodsIds(orderGoodsIds);*/
        return result;
    }

    /**----------------------------------------------------发货通知单相关逻辑------start--------------------------------------*/

    /**
     * 修改发货通知单
     * cn/gomro/core/bizes/vmi/service/impl/DeliverNoticeService.update
     *
     * @param deliverNoticeVO
     * @param submit
     * @return
     */
    public SingleResponse<BO> updateDeliveryNotice(DeliverNoticeVO deliverNoticeVO, Boolean submit) {

        if (deliverNoticeValidate(deliverNoticeVO)) {
            Map<String, Object> deliverNoticeParam = new HashMap<>();

            if (null == deliverNoticeVO.getId()) throw new RuntimeException("发货通知单不存在！");
            Map<String, Object> dne = selectModelById(deliverNoticeVO.getId(), AppConst.COMMODITYMATERIALS, ModelConst.T_DELIVER_NOTICE);

            if (!DeliverNoticeEnum.NEW.id.toString().equals(dne.get("approvalStatus")))
                throw new RuntimeException("只有新建发货通知单才可修改！");
            deliverNoticeParam.put("id", deliverNoticeVO.getId());
            deliverNoticeParam.put("address", deliverNoticeVO.getAddress());
            deliverNoticeParam.put("phone", deliverNoticeVO.getPhone());
            deliverNoticeParam.put("postal", deliverNoticeVO.getPostal());
            deliverNoticeParam.put("receiver", deliverNoticeVO.getReceiver());
            deliverNoticeParam.put("request_arrival_time", deliverNoticeVO.getRequestArrivalTime());
            if (submit) {
                deliverNoticeParam.put("approvalStatus", DeliverNoticeEnum.SUBMIT.id.toString());
            }
            deliverNoticeVO.getMaterialNoticeVOS().forEach(mv -> {
                Map<String, Object> one = JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_MATERIAL_NOTICE).selectField("*")
                        .eq("id", mv.getId()).queryForMap();
                if (null == one) throw new RuntimeException("发货通知商品" + mv.getId() + "不存在！");
                Map<String, Object> materialNoticeParam = new HashMap<>();
                materialNoticeParam.put("min_num", mv.getMinNum());
                if (submit) {
                    materialNoticeParam.put("approvalStatus", MaterialNoticeEnum.PACKING.id.toString());
                }
                JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_MATERIAL_NOTICE)
                        .putFieldAndVal(materialNoticeParam).eq("id", mv.getId()).update();
            });
            deliverNoticeParam.put("deleted", !Objects.isNull(dne.get("deleted")) && dne.get("deleted").equals("1") ? true : false);
            return BoServiceUtils.updateMainBo(ModelConst.T_DELIVER_NOTICE, deliverNoticeParam);
        }
        return null;
    }

    /**
     * 验证代码
     *
     * @param deliverNoticeVO
     * @return
     */
    private Boolean deliverNoticeValidate(DeliverNoticeVO deliverNoticeVO) {

        //发货通知单验证
        if (null != deliverNoticeVO) {
            if (null == deliverNoticeVO.getCustomerId()) throw new RuntimeException("使用方id获取异常！");
            if (null == deliverNoticeVO.getVendorId()) throw new RuntimeException("寄售方id获取异常！");

            if (null == deliverNoticeVO.getAddress() || "" == deliverNoticeVO.getAddress())
                throw new RuntimeException("收货地址不能为空！");
            if (null == deliverNoticeVO.getPhone() || "" == deliverNoticeVO.getPhone())
                throw new RuntimeException("电话不能为空！");
            if (null == deliverNoticeVO.getRequestArrivalTime() || System.currentTimeMillis() > deliverNoticeVO.getRequestArrivalTime().getTime())
                throw new RuntimeException("请求到货时间无效！");


            List<MaterialNoticeVO> materialNoticeVOS = deliverNoticeVO.getMaterialNoticeVOS();

            //发货物料验证
            if (null != materialNoticeVOS && 0 < materialNoticeVOS.size()) {

                materialNoticeVOS.forEach(material -> {

                    if (null == material.getGoodsId()) throw new RuntimeException("商品id为空！");

                    if (!RegexUtils.notNull(material.getBrand()))
                        throw new RuntimeException("品牌不能为空！");
                    if (!RegexUtils.notNull(material.getName()))
                        throw new RuntimeException("名称不能为空！");
                    if (!RegexUtils.notNull(material.getModel()))
                        throw new RuntimeException("型号不能为空！");
                    if (!RegexUtils.notNull(material.getUnit()))
                        throw new RuntimeException("单位不能为空！");

                    if (null == material.getMinNum() || material.getMinNum().compareTo(BigDecimal.ZERO) < 1)
                        throw new RuntimeException("最小发货数量不能为空！");
                    /*if (null == material.getSafetyStockNum() || material.getSafetyStockNum().compareTo(BigDecimal.ZERO) < 1)
                        throw new RuntimeException("安全库存数不能为空！");*/
                    Map<String, Object> goods = JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODS_PURCHASE).selectField("*")
                            .eq("id", material.getGoodsId()).queryForMap();
                    if (CollectionUtils.isEmpty(goods)) throw new RuntimeException("来源商品不存在！");
                    if (goods.get("enabled").equals("0"))
                        throw new RuntimeException("来源商品已不可采购，请重新询价！");
                    if (BigDecimalUtils.isNull(goods.get("pretax_price")).compareTo(material.getPretaxPrice()) != 0)
                        throw new RuntimeException("税前单价与来源商品税前单价不一致！");
                    if (BigDecimalUtils.isNull(goods.get("price")).compareTo(material.getPrice()) != 0)
                        throw new RuntimeException("单价与来源商品单价不一致！");
                    if (BigDecimalUtils.isNull(goods.get("tax_rate")).compareTo(material.getTaxRate()) != 0)
                        throw new RuntimeException("税率与来源商品税率不一致！");
                });
            } else {
                throw new RuntimeException("发货通知商品不存在！");
            }
        } else {
            throw new RuntimeException("发货通知单不存在！");
        }
        return true;
    }

    /**
     * 提交通知单
     * cn/gomro/core/bizes/vmi/service/impl/DeliverService.submit
     *
     * @param ids
     * @return
     */
    public void submitDeliveryNotice(Collection<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new RuntimeException("参数不能为空！");
        }
        for (String id : ids) {
            Map<String, Object> nc = selectModelById(id, AppConst.COMMODITYMATERIALS, ModelConst.T_DELIVER_NOTICE);
            if (null == nc) throw new RuntimeException("发货通知信息不存在！");
            if (!DeliverNoticeEnum.NEW.id.toString().equals(nc.get("approvalStatus")))
                throw new RuntimeException("只有新建发货通知单才可提交！");
            Map<String, Object> deliverNoticeParam = new HashMap<>();
            deliverNoticeParam.put("approvalStatus", DeliverNoticeEnum.SUBMIT.id.toString());
            deliverNoticeParam.put("id", nc.get("id"));
            BoServiceUtils.updateMainBo(ModelConst.T_DELIVER_NOTICE, deliverNoticeParam);
            JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_MATERIAL_NOTICE)
                    .putFieldAndVal("approvalStatus", MaterialEnum.DELIVERD.id.toString()).eq("deliver_notice_id", nc.get("id")).update();
        }
    }

    /**
     * 取消发货单
     * cn/gomro/core/bizes/vmi/service/impl/DeliverService.cancle
     *
     * @param ids
     * @return
     */
    public void cancelDeliveryNotice(Collection<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new RuntimeException("参数不能为空！");
        }
        for (String id : ids) {
            Map<String, Object> nc = selectModelById(id, AppConst.COMMODITYMATERIALS, ModelConst.T_DELIVER_NOTICE);
            if(CollectionUtils.isEmpty(nc)){
                throw new RuntimeException("发货通知数据不存在！");
            }
            JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_DELIVER_NOTICE)
                    .putFieldAndVal("approvalStatus", DeliverNoticeEnum.CLOSE.id.toString())
                    .putFieldAndVal("deleted", true).eq("id", id).update();

            JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_MATERIAL_NOTICE)
                    .putFieldAndVal("approvalStatus", DeliverNoticeEnum.CLOSE.id.toString())
                    .putFieldAndVal("deleted", true).eq("deliver_notice_id", id).update();
        }
    }

    /**
     * 保存发货单
     * cn/gomro/core/bizes/vmi/service/impl/DeliverService.save
     *
     * @param deliverVO
     * @param submit
     * @return
     */
    public SingleResponse<BO> saveDelivery(DeliverVO deliverVO, Boolean submit) {
//        if (sessionUser.isPm()) throw new RuntimeException("平台不可操作！");

        Map<String, Object> deliverEntity;
        deliverValidate(deliverVO);
        deliverVO.setMemberId(getSelectorFormat());

        if (submit) {
            deliverVO.setDeliverStatus(DeliverEnum.SUBMIT);
        } else {
            deliverVO.setDeliverStatus(DeliverEnum.NEW);
        }

        deliverEntity = DeliverVO.voToEntity(deliverVO);

        List<Map<String, Object>> materialEntities = deliverVO.getMaterialVOS().stream().map(MaterialVO::voToEntity).collect(Collectors.toList());

        for (Map<String, Object> materialEntity : materialEntities) {
            //客户待入库数量+库存数不可大于最大库存量
            String goodsId = (String) materialEntity.get("goods_id");
            BigDecimal sumNum = BigDecimal.ZERO;
            try {
                String getUnReceiveCountSql = "select sum(m.num) from " + getTableName(ModelConst.T_MATERIAL) + " m" +
                        " INNER JOIN " + getTableName(ModelConst.T_DELIVER) + " d on m.deliver_id = d.id" +
                        " where m.goods_id =" + goodsId + " and m.deleted = '0' and d.status ='2'";
                sumNum = jdbcTemplate.queryForObject(getUnReceiveCountSql, new HashMap<>(), BigDecimal.class);
            } catch (DataAccessException e) {
                e.printStackTrace();
            }
            Map<String, Object> stockParam = new HashMap<>();
            stockParam.put("goods_id", goodsId);
            List<Map<String, Object>> stockList = selectModelByMaps(Collections.singletonList(stockParam), ModelConst.T_STOCK);
            Map<String, Object> stock = null;
            if (!CollectionUtils.isEmpty(stockList)) {
                stock = stockList.get(0);
            }
            sumNum = BigDecimalUtils.add(null == sumNum ? BigDecimal.ZERO : sumNum, null == stock ? BigDecimal.ZERO : BigDecimalUtils.isNull(stock.get("num")));

            Map<String, Object> goods = selectModelById(goodsId, AppConst.COMMODITYMATERIALS, ModelConst.T_GOODS_PURCHASE);
            if (null == goods || goods.isEmpty()) throw new RuntimeException("组织采购单不存在！");

            Map<String, Object> inquiryGoods = getInquiryGoodsByGoodsId(goodsId);
            if (sumNum.compareTo(BigDecimalUtils.isNull(inquiryGoods.get("maximum_stock"))) != -1) {
                throw new RuntimeException("客户库存充足不需要补货");
            }
            materialEntity.put("customer_id", deliverVO.getCustomerId());
            materialEntity.put("customer_name", Objects.isNull(deliverVO.getCustomerId()) ? null : deliverVO.getCustomerId().getName());
            materialEntity.put("vendor_id", deliverVO.getVendorId());
            materialEntity.put("vendor_name", Objects.isNull(deliverVO.getVendorId()) ? null : deliverVO.getVendorId().getName());
            materialEntity.put("member_id", deliverVO.getMemberId());
            if (submit) {
                materialEntity.put("material_status", MaterialEnum.DELIVERD.name());
            } else {
                materialEntity.put("material_status", MaterialEnum.NEW.name());
            }
            materialEntity.put("total", FinancialCalculationUtils.calculateTotalByPretaxPrice(BigDecimalUtils.isNull(materialEntity.get("pretax_price")),
                    BigDecimalUtils.isNull(materialEntity.get("tax_rate")), BigDecimalUtils.isNull(materialEntity.get("num"))));
            materialEntity.put("total", FinancialCalculationUtils.calculatePretaxTotalByPretaxPrice(BigDecimalUtils.isNull(materialEntity.get("pretax_price")),
                    BigDecimalUtils.isNull(materialEntity.get("num"))));
        }
        SingleResponse<BO> response = BoServiceUtils.createBo(ModelConst.T_DELIVER, Collections.singletonList(deliverEntity));
        if (!response.isSuccess()) {
            throw new RuntimeException("发货单创建失败！");
        }
        for (Map<String, Object> materialParam : materialEntities) {
            materialParam.put("deliver_id", response.getData().getBizObjectId());
        }
        BoServiceUtils.createBo(ModelConst.T_MATERIAL, materialEntities);
        //创建发货单的同时修改发货通知单状态，改为已发货
        Map<String, Object> deliveryNoticeParam = new HashMap<>();
        deliveryNoticeParam.put("approvalStatus", DeliverNoticeEnum.DELIVERD.id.toString());
        JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_DELIVER_NOTICE)
                .putFieldAndVal(deliveryNoticeParam).eq("id", deliverVO.getDeliverNoticeId()).update();
        return response;
    }

    /**
     * 验证代码
     *
     * @param deliverVO
     * @return
     */
    private Boolean deliverValidate(DeliverVO deliverVO) {

        //发货单验证
        if (null != deliverVO) {
            if (null == deliverVO.getCustomerId()) throw new RuntimeException("使用方id获取异常！");
            if (null == deliverVO.getVendorId()) throw new RuntimeException("寄售方id获取异常！");

            if (null == deliverVO.getDeliverNoticeId()) throw new RuntimeException("发货单号不能为空！");
            if (null == deliverVO.getWaybill()) throw new RuntimeException("物流名称不能为空！");
            if (null == deliverVO.getLogistics()) throw new RuntimeException("物流单号不能为空！");

            List<MaterialVO> materialVOS = deliverVO.getMaterialVOS();

            //发货物料验证
            if (null != materialVOS && 0 < materialVOS.size()) {

                materialVOS.forEach(material -> {

                    if (null == material.getGoodsId()) throw new RuntimeException("商品id为空！");

                    if (!RegexUtils.notNull(material.getBrand()))
                        throw new RuntimeException("品牌不能为空！");
                    if (!RegexUtils.notNull(material.getName()))
                        throw new RuntimeException("名称不能为空！");
                    if (!RegexUtils.notNull(material.getModel()))
                        throw new RuntimeException("型号不能为空！");
                    if (!RegexUtils.notNull(material.getUnit()))
                        throw new RuntimeException("单位不能为空！");
                    if (null == material.getPretaxPrice()) throw new RuntimeException("税前单价不能为空！");

                    if (null == material.getPrice()) throw new RuntimeException("单价不能为空！");
                    if (null == material.getNum()) throw new RuntimeException("发货数量不能为空！");
                });
            } else {
                throw new RuntimeException("发货商品不存在！");
            }
        } else {
            throw new RuntimeException("发货单不存在！");
        }
        return true;
    }

    /**----------------------------------------------------发货通知单相关逻辑------end--------------------------------------*/


    /**----------------------------------------------------库存、库存单据相关逻辑------start--------------------------------------*/
    /**
     * 保存入库单
     * cn/gomro/core/bizes/vmi/service/impl/StockService.save
     *
     * @param stockBillVO
     * @return
     */
    public SingleResponse<BO> saveStockBillVO(StockBillVO stockBillVO) {
//        if (sessionUser.isPm()) throw new VmiException("平台不可操作！");

        if (null == stockBillVO) throw new RuntimeException("单据不存在！");

        Map<String, Object> stockBillMap;
        validateStockBill(null, stockBillVO);

        if (StockBillTypeEnum.CHECK.name().equals(stockBillVO.getType())) {
            //盘点单新建平台审核
            stockBillVO.setStockBillStatus(StockBillStatusEnum.PM_CHECK);
        } else {
            stockBillVO.setStockBillStatus(StockBillStatusEnum.WOKING);
        }

        stockBillMap = StockBillVO.voToEntity(stockBillVO);
        SelectorFormat memberId = getSelectorFormat(null, UnitType.USER);
        stockBillMap.put("member_id", memberId);
        stockBillMap.put("member_name", memberId.getName());
        SelectorFormat customerId = stockBillVO.getCustomerId();
        SelectorFormat vendorId = stockBillVO.getVendorId();
        if (null != stockBillMap.get("deleted") && stockBillMap.get("deleted").equals("1")) {
            stockBillMap.put("deleted", true);
        } else {
            stockBillMap.put("deleted", false);
        }
        SingleResponse<BO> bo = BoServiceUtils.createBo(ModelConst.T_STOCK_BILL, Collections.singletonList(stockBillMap));

        stockBillVO.getStockBillMaterialVOS().stream().map(StockBillMaterialDto::voToEntity).forEach(material -> {
            material.put("customer_id", customerId);
            material.put("vendor_id", vendorId);
            material.put("member_id", memberId);
            material.put("vendor_name", vendorId.getName());
            material.put("customer_name", customerId.getName());
            material.put("stock_bill_id", bo.getData().getBizObjectId());
//            material.put("receive_num", material.get("num"));
            log.info("------------------material:"+material);
            BoServiceUtils.createBo(ModelConst.T_STOCK_BILL_MATERIAL, Collections.singletonList(material));
        });
        //创建入库相关单据，盘点单不允许直接操作库存，需要审批到已盘点才可以更新库存
        if (!StockBillTypeEnum.CHECK.name().equals(stockBillVO.getType())) {
            manageStock(stockBillVO, false);
        }
        return bo;
    }

    /**
     * 盘点单审核
     * @author zhanjinhua
     * @date 2021/10/13
     * @param * @param stockBillVO
     * @return * @return: com.alibaba.cola.dto.SingleResponse<com.authine.mvp.app.launcher.dto.bo.response.BO>
     */
    public void stockBillExamineVo(StockBillVO stockBillVO) {

        if (null == stockBillVO) {
            throw new RuntimeException("单据不存在！");
        }
        if (null == stockBillVO.getIds()) {
            throw new RuntimeException("单据id获取异常！");
        }
        if (null == stockBillVO.getIsOk()) {
            throw new RuntimeException("审批结果获取异常！");
        }
        Map<String, List<String>> param = new HashMap<>();
        param.put("id",stockBillVO.getIds());
        List<Map<String, Object>> stockBillList = selectModelByIn(param, getTableName(ModelConst.T_STOCK_BILL));
        if (stockBillList == null){
            throw new RuntimeException("单据不存在！");
        }
        stockBillList.forEach(stockBill -> {
            //已盘点和已关闭不能再次进行审核
            if(StockBillStatusEnum.WOKING.name().equals(stockBill.get("stock_bill_status"))||
                    StockBillStatusEnum.CLOSED.name().equals(stockBill.get("stock_bill_status"))){
                throw new RuntimeException("盘点单" + stockBill.get("id") + "不在审批中!");
            }
        });
        SessionUser sessionUser = new SessionUser();
        if (null == sessionUser.get()) throw new BizException("未获取到登录信息!");
        stockBillList.forEach(stockBill -> {
            Map<String, Object> stockBillMap = new HashMap<>();
            //平台审批
            if (StockBillStatusEnum.PM_CHECK.name().equals(stockBill.get("stock_bill_status"))) {
                Assert.isTrue(sessionUser.isPm(), "盘点单" + stockBill.get("id") + "只有平台角色才可以审批!");
                //同意 平台->客户
                if (stockBillVO.getIsOk()) {
                    stockBillMap.put("stock_bill_status", StockBillStatusEnum.CUSTOMER_CHECK.name());
                } else {
                    stockBillMap.put("stock_bill_status", StockBillStatusEnum.CLOSED.name());
                }
            //客户审批
            } else if (StockBillStatusEnum.CUSTOMER_CHECK.name().equals(stockBill.get("stock_bill_status"))) {
                Assert.isTrue(sessionUser.isCustomer(), "盘点单" + stockBill.get("id") + "只有客户角色才可以审批!");
                //同意 客户->已盘点
                if (stockBillVO.getIsOk()) {
                    stockBillMap.put("stock_bill_status", StockBillStatusEnum.WOKING.name());
                    stockBill.put("stock_bill_status", StockBillStatusEnum.WOKING.name());
                    StockBillVO manageStockBill = getStockBillVOByParamMap(stockBill);
                    manageStock(manageStockBill, false);
                } else {
                    stockBillMap.put("stock_bill_status", StockBillStatusEnum.CLOSED.name());
                }
            } else {
                //其他类型无法审批
                throw new RuntimeException("盘点单" + stockBill.get("id") + "不在审批中!");
            }
            stockBillMap.put("comment", stockBillVO.getComment());
            JdbcTemplateUtils.builder(ModelConst.T_STOCK_BILL)
                    .putFieldAndVal(stockBillMap).eq("id", stockBill.get("id")).update();
        });
    }


    /**
     * entry转使用单据
     * @author zhanjinhua
     * @date 2021/10/14
     * @param * @param stockBillVOMap:
     * @return * @return: com.authine.cloudpivot.ext.dto.StockBillVO
     */
    public StockBillVO getStockBillVOByParamMap(Map<String, Object> stockBillVOMap){
        StockBillVO stockBillVO = new StockBillVO();
        stockBillVO.setVendorId(null == stockBillVOMap.get("vendor_id") ? null :
                JSON.parseObject((String) stockBillVOMap.get("vendor_id"), SelectorFormat.class));
        stockBillVO.setMemberId(getSelectorFormat(null, UnitType.USER));
        stockBillVO.setCustomerId(null == stockBillVOMap.get("customer_id") ? null :
                JSON.parseObject((String) stockBillVOMap.get("customer_id"), SelectorFormat.class));
        stockBillVO.setId(null == stockBillVOMap.get("id") ? null : stockBillVOMap.get("id").toString());
        stockBillVO.setType(null == stockBillVOMap.get("type") ? null : stockBillVOMap.get("type").toString());
        stockBillVO.setStockBillStatus(null == stockBillVOMap.get("stock_bill_status") ? null :
                StockBillStatusEnum.get(stockBillVOMap.get("stock_bill_status").toString()));
        stockBillVO.setSrcId(null == stockBillVOMap.get("src_id") ? null : stockBillVOMap.get("src_id").toString());
        Map<String, List<String>> stockBillMaterialParam = new HashMap<>();
        List<String> ids = new ArrayList<>();
        ids.add(stockBillVOMap.get("id").toString());
        stockBillMaterialParam.put("stock_bill_id",ids);
        //根据id查询库存相关单据物料集合
        List<Map<String, Object>> stockBillMaterialList = selectModelByIn(stockBillMaterialParam, getTableName(ModelConst.T_STOCK_BILL_MATERIAL));
        List<StockBillMaterialDto> stockBillMaterialVOS = new ArrayList<>();
        stockBillMaterialList.forEach(stockBillMaterial->{
            stockBillMaterialVOS.add(StockBillMaterialDto.entryToVo(stockBillMaterial));
        });
        stockBillVO.setStockBillMaterialVOS(stockBillMaterialVOS);
        return stockBillVO;
    }

    /**
     * 库存是否为盘点中
     *
     * @param goodsId
     * @return
     */
    public boolean isWorking(String goodsId) {
        String stockBillMaterialDB = getTableName(ModelConst.T_STOCK_BILL_MATERIAL);
        String stockBillDB = getTableName(ModelConst.T_STOCK_BILL);
        String stockBillMaterialSql = "select a.id from " + stockBillMaterialDB + " a ,"+
                stockBillDB + " b " +
                " where a.stock_bill_id = b.id and a.deleted = '0' AND b.deleted = '0' " +
                "AND stock_bill_status IN ('PM_CHECK','CUSTOMER_CHECK') " +
                "and a.goods_id = '" + goodsId + "'";
        List<Map<String, Object>> stockBillMaterialList = jdbcTemplate.queryForList(stockBillMaterialSql, new HashMap<>());
        if (CollectionUtils.isEmpty(stockBillMaterialList)) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 验证代码
     *
     * @param stockVO
     * @return
     */
    private Boolean validateStockBill(StockVO stockVO, StockBillVO stockBillVO) {

        //库存验证
        if (null != stockVO) {
            if (null == stockVO.getCustomerId()) throw new RuntimeException("使用方id获取异常！");
            if (null == stockVO.getVendorId()) throw new RuntimeException("寄售方id获取异常！");

            if (!RegexUtils.notNull(stockVO.getBrand())) throw new RuntimeException("品牌不能为空！");
            if (!RegexUtils.notNull(stockVO.getName())) throw new RuntimeException("名称不能为空！");
            if (!RegexUtils.notNull(stockVO.getModel())) throw new RuntimeException("型号不能为空！");
            if (!RegexUtils.notNull(stockVO.getUnit())) throw new RuntimeException("单位不能为空！");

        }
        //库存单据验证
        if (null != stockBillVO) {
            if(null == stockBillVO.getMemberId()){
                SelectorFormat memberId = getSelectorFormat(null, UnitType.USER);
                stockBillVO.setMemberId(memberId);
            }

            //仅入库单有寄售方id
            if (null == stockBillVO.getVendorId() && !stockBillVO.getType().equals(StockBillTypeEnum.RECEIVE.name())) {
                SelectorFormat vendorId = getSelectorFormat(null, UnitType.DEPARTMENT);
                stockBillVO.setVendorId(vendorId);
            }

            if (null == stockBillVO.getSrcId()) throw new RuntimeException("来源单据id不存在！");

            List<StockBillMaterialDto> stockBillMaterialVOS = stockBillVO.getStockBillMaterialVOS();

            if (null != stockBillMaterialVOS && 0 < stockBillMaterialVOS.size()) {
                stockBillMaterialVOS.forEach(material -> {

                    if (null == material.getGoodsId()) throw new RuntimeException("商品id不存在！");
                    if (null == material.getNum()) throw new RuntimeException("数量不能为空！");

                    if (null == material.getPretaxPrice()) throw new RuntimeException("税前单价不能为空！");
                    if (null == material.getPrice()) throw new RuntimeException("单价不能为空！");
                    if (null == material.getTaxRate()) throw new RuntimeException("税率不能为空！");
                    if (null == material.getType()) throw new RuntimeException("类型不能为空！");

                    if (!RegexUtils.notNull(material.getBrand()))
                        throw new RuntimeException("品牌不能为空！");
                    if (!RegexUtils.notNull(material.getName()))
                        throw new RuntimeException("名称不能为空！");
                    if (!RegexUtils.notNull(material.getModel()))
                        throw new RuntimeException("型号不能为空！");
                    if (!RegexUtils.notNull(material.getUnit()))
                        throw new RuntimeException("单位不能为空！");
                    if(isWorking(material.getGoodsId())){
                        throw new RuntimeException("操作失败：库存商品【" + material.getId() + "】正在盘点中！");
                    }
                });

            } else {
                throw new RuntimeException("商品信息不存在！");
            }
        }

        return true;
    }

    /**
     * cn/gomro/core/bizes/vmi/service/impl/StockService.manageStock
     * 根据使用单据调整库存
     */
    private void manageStock(StockBillVO stockBillVO, Boolean approve) {
        //加入/扣减库存
        List<StockBillMaterialDto> stockBillMaterialList = stockBillVO.getStockBillMaterialVOS();

        List<Map<String, Object>> stockLogList = new ArrayList<>();

        Boolean checkPass = true;
        //审批中的盘点单和未通过的盘点单
        if (StockBillTypeEnum.CHECK.name().equals(stockBillVO.getType()) &&
                (StockBillStatusEnum.CUSTOMER_CHECK.name().equals(stockBillVO.getStockBillStatus().name()) ||
                        StockBillStatusEnum.PM_CHECK.name().equals(stockBillVO.getStockBillStatus().name()) ||
                        StockBillStatusEnum.CLOSED.name().equals(stockBillVO.getStockBillStatus().name()))) {
            //不进行库存相关操作
            checkPass = false;
        }

        for (StockBillMaterialDto material : stockBillMaterialList) {
            String goodsId = material.getGoodsId();
            List<Map<String, Object>> goodsList = JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODS_PURCHASE).selectField("*").eq("id", goodsId).queryForList();
            if (CollectionUtils.isEmpty(goodsList)) throw new RuntimeException("协议商品不存在！");
            Map<String, Object> goods = goodsList.get(0);

            //最大库存量
            Map<String, Object> map = getInquiryGoodsByGoodsId(goodsId);
            BigDecimal maximumStock = null == map || map.isEmpty() ? null : BigDecimalUtils.isNull(map.get("maximum_stock"));
            //库存商品
            List<Map<String, Object>> resultStock = JdbcTemplateUtils.builder(ModelConst.T_STOCK).selectField("*").eq("goods_id", goodsId).queryForList();

            String stockId;
            //获取库存
            if (CollectionUtils.isEmpty(resultStock)) {
                //没有原库存则新增
                material.setOrginalNum(BigDecimal.ZERO);
                Map<String, Object> stockParam = StockBillMaterialDto.voToEntity(material);
                stockParam.put("maximum_stock", maximumStock);
                stockParam.put("stock_status", StockEnum.PERFECT.name());
                stockParam.put("safety_stock_num", BigDecimalUtils.isNull(goods.get("safety_stock_num")));
                stockParam.put("enable", true);
                SelectorFormat memberId = bOValidatedAndFormatService.getCurrentUser();
                stockParam.put("member_id", memberId);
                stockParam.put("member_name", memberId.getName());
                SelectorFormat customerIds = stockBillVO.getCustomerId();
                stockParam.put("customer_id", customerIds);
                stockParam.put("customer_name", customerIds.getName());
                SelectorFormat vendorIds = stockBillVO.getVendorId();
                stockParam.put("vendor_id", vendorIds);
                stockParam.put("vendor_name", vendorIds.getName());
                SingleResponse<BO> bo = BoServiceUtils.createBo(ModelConst.T_STOCK, Collections.singletonList(stockParam));
                stockId = bo.getData().getBizObjectId();
            } else {
                Map<String, Object> seParam = new HashMap<>();
                Map<String, Object> se = resultStock.get(0);
                seParam.put("id", se.get("id"));
                //库存商品启用
                if (se.get("enable").equals("0") && checkPass && !approve)
                    throw new RuntimeException("操作失败：库存商品【" + se.get("id") + "】正在盘点中！");

                material.setOrginalNum(null == map ? BigDecimal.ZERO : BigDecimalUtils.isNull(map.get("num")));

                stockId = (String) se.get("id");

                material.setVendorId(null == se.get("vendor_id") ? null : JSON.parseObject((String) se.get("vendor_id"), SelectorFormat.class));
                if (null != material.getType()) {
                    if (material.getType().equals(StockBillMaterialTypeEnum.RECEIVE.name())) {
                        Map<String, Object> me = JdbcTemplateUtils.builder(ModelConst.T_MATERIAL)
                                .selectField("*").eq("id", material.getSrcId()).queryForMap();
                        if (material.getNum().compareTo(BigDecimalUtils.isNull(me.get("num"))) == 1)
                            throw new RuntimeException("入库数量不可大于发货数量！");
                        //入库，加库存数量
                        seParam.put("num", BigDecimalUtils.add(material.getNum(), BigDecimalUtils.isNull(se.get("num"))).toPlainString());

                    } else if (material.getType().equals(StockBillMaterialTypeEnum.USE.name())) {
                        //领用单，减库存数量
                        if (BigDecimalUtils.isNull(se.get("num")).compareTo(material.getUseNum()) < -1)
                            throw new RuntimeException("库存不足！");
                        seParam.put("num", BigDecimalUtils.sub(BigDecimalUtils.isNull(se.get("num")), material.getUseNum()).toPlainString());

                    } else if (material.getType().equals(StockBillMaterialTypeEnum.RETURN.name())) {
                        //退料，减少领用单的领用数量
                        Map<String, Object> sbme = selectModelById(material.getId(), ModelConst.T_STOCK_BILL_MATERIAL);
                        if (material.getReturnNum().compareTo(BigDecimalUtils.sub(BigDecimalUtils.isNull(sbme.get("use_num")), BigDecimalUtils.isNull(sbme.get("return_num")))) == 1)
                            throw new RuntimeException("可退的领用数量不足！");
                        Map<String, Object> sbmeParam = new HashMap<>();
                        sbmeParam.put("use_num", BigDecimalUtils.sub(BigDecimalUtils.isNull(sbme.get("use_num")), material.getReturnNum()).toPlainString());
                        sbmeParam.put("id", material.getId());
                        BoServiceUtils.updateMainBo(ModelConst.T_STOCK_BILL_MATERIAL, sbmeParam);
                        //增加库存数量
                        seParam.put("num", BigDecimalUtils.add(BigDecimalUtils.isNull(se.get("num")), material.getReturnNum()).toPlainString());

                    } else if (material.getType().equals(StockBillMaterialTypeEnum.CHECK_LOSS.name()) ||
                            material.getType().equals(StockBillMaterialTypeEnum.CHECK_PROFIT.name()) || material.getType().equals(StockBillMaterialTypeEnum.CHECK.name())) {
                        //盘点单，调整仓库数量与盘点单一致
                        if (checkPass) {
                            seParam.put("num", BigDecimalUtils.sub(material.getOrginalNum(), material.getNum()).toPlainString());
                            //启用库存商品
                            seParam.put("enable", true);
                        } else {
                            //禁用库存商品
                            seParam.put("enable", false);
                        }
                    }
                }
                //重新计算金额
                seParam.put("pretax_total", FinancialCalculationUtils.calculatePretaxTotalByPretaxPrice(BigDecimalUtils.isNull(se.get("pretax_price")), BigDecimalUtils.isNull(se.get("num"))));
                seParam.put("total", FinancialCalculationUtils.calculateTotalByPretaxPrice(BigDecimalUtils.isNull(se.get("pretax_price")), BigDecimalUtils.isNull(se.get("tax_rate")), BigDecimalUtils.isNull(se.get("num"))));
                seParam.put("tax_payable", FinancialCalculationUtils.calculateTaxPayableByPretaxPrice(BigDecimalUtils.isNull(se.get("pretax_price")), BigDecimalUtils.isNull(se.get("tax_rate")), BigDecimalUtils.isNull(se.get("num"))));

                if (checkPass) {
                    BoServiceUtils.updateMainBo(ModelConst.T_STOCK, Collections.singletonList(seParam));
                }
            }

            StockLogEnum type;

            if (null != material.getType()) {
                // 增加库存操作日志
                if (material.getType().equals(StockBillMaterialTypeEnum.USE)) {
                    type = StockLogEnum.USER;
                } else if (material.getType().equals(StockBillMaterialTypeEnum.RETURN)) {
                    type = StockLogEnum.RETURN;
                } else if (material.getType().equals(StockBillMaterialTypeEnum.RECEIVE)) {
                    type = StockLogEnum.RECEIVE;
                } else if (material.getType().equals(StockBillMaterialTypeEnum.CHECK_LOSS)) {
                    type = StockLogEnum.CHECK_LOSS;
                } else if (material.getType().equals(StockBillMaterialTypeEnum.CHECK_PROFIT)) {
                    type = StockLogEnum.CHECK_PROFIT;
                } else if (material.getType().equals(StockBillMaterialTypeEnum.CHECK)) {
                    type = StockLogEnum.CHECK;
                } else {
                    type = StockLogEnum.ALL;
                }

//            stockLogList.add(new StockLogEntity(material.getMemberId(), stockId, type, material.getNum(), material.getTaxRate(),
//                    material.getPretaxPrice(), material.getPrice(), material.getPretaxTotal(), material.getTotal(), material.getTaxPayable()));

            }
        }
        //领用改变发货单状态
        if (stockBillVO.getType().equals(StockBillTypeEnum.RECEIVE.name())) {
            Map<String, Object> de = selectModelById(stockBillVO.getSrcId(), ModelConst.T_DELIVER);
            if (null == de) throw new RuntimeException("发货单不存在！");
            de.put("deliver_status", DeliverEnum.DONE.name());
            JdbcTemplateUtils.builder(ModelConst.T_DELIVER).putFieldAndVal("deliver_status", DeliverEnum.DONE.name())
                    .eq("id", stockBillVO.getSrcId()).update();
        }
        //保存仓库操作明细
        if (checkPass) {
//            iStockLogRepository.saveAll(stockLogList);
        }
    }

    /**
     * 根据消耗创建订单
     * cn/gomro/core/bizes/vmi/service/impl/StockService.buildOrder
     *
     * @param idList
     * @return
     */
    public Map<String, Object> buildOrder(List<String> idList) {
        if (null == idList || idList.isEmpty()) throw new RuntimeException("明细id为空!");

        List<Map<String, Object>> sbmeList = getStockBillMaterialByIds(idList);

        if (null == sbmeList || sbmeList.isEmpty()) throw new RuntimeException("明细单据不存在!");

        Map<String, Object> customerOrder = new HashMap<>();
        List<Map<String, Object>> vendorOrders = new ArrayList<>();

        List<String> idsList = new ArrayList<>();

        List<StockBillMaterialDto> stockBillMaterialVOS = new ArrayList<>();
        for (Map<String, Object> sme : sbmeList) {

            //非客户承担不结算
            if (!sme.get("bear_type").equals(BearTypeEnum.CUSTOMER_BEAR.name())) {
                continue;
            }

            //非盘亏、非领用、非退料不结算
            if (!sme.get("type").equals(StockBillMaterialTypeEnum.CHECK_LOSS.name()) && !sme.get("type").equals(StockBillMaterialTypeEnum.USE.name()) && !sme.get("type").equals(StockBillMaterialTypeEnum.RETURN.name())) {
                continue;
            }

            //参与结算的记录
            idsList.add((String) sme.get("id"));

            if (null == stockBillMaterialVOS || stockBillMaterialVOS.isEmpty()) {
                stockBillMaterialVOS.add(new StockBillMaterialDto((SelectorFormat) sme.get("vendor_id"), (String) sme.get("goods_id"), BigDecimalUtils.isNull(sme.get("num"))));
            } else {
                Boolean flag = true;
                for (StockBillMaterialDto sbmVOS : stockBillMaterialVOS) {
                    if (sbmVOS.getGoodsId().equals(sme.get("goods_id"))) {
                        sbmVOS.setNum(BigDecimalUtils.add(sbmVOS.getNum(), BigDecimalUtils.isNull(sme.get("num"))));
                        flag = false;
                    }
                }
                if (flag) {
                    stockBillMaterialVOS.add(new StockBillMaterialDto((SelectorFormat) sme.get("vendor_id"), (String) sme.get("goods_id"), BigDecimalUtils.isNull(sme.get("num"))));
                }
            }
        }

        //整理消耗数据，订单处理完后，通过此ids改变原单据状态
        String ids = org.apache.commons.lang3.StringUtils.join(idsList, ",");
        customerOrder.put("vmi_ids", ids);

        //创建订单
        for (StockBillMaterialDto sme : stockBillMaterialVOS) {

            String goodsId = sme.getGoodsId();
            SelectorFormat vendorId = sme.getVendorId();
            BigDecimal num = sme.getNum();
            String costCenterName = "";

            Map<String, Object> orderGoods = new HashMap<>();

            Map<String, Object> goods =JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODS_PURCHASE).selectField("*")
                    .eq("id", goodsId).queryForMap();
            if (CollectionUtils.isEmpty(goods)) throw new RuntimeException("来源vmi商品不存在！");

            //最大库存量
            Map<String, Object> map = getInquiryGoodsByGoodsId(goodsId);
            costCenterName = null == map || map.isEmpty() ? null : (String) map.get("cost_center_name");

            /*if (null != goods.getQuotationGoods()) {
                costCenterName = goods.getQuotationGoods().getInquiryGoods().getInquiry().getCostCenterName();
            }*/

            orderGoods.put("category", null == goods.get("catalog") ? "" : goods.get("catalog"));
            orderGoods.put("brand", goods.get("brand"));
            orderGoods.put("name", goods.get("name"));
            orderGoods.put("model", goods.get("model"));
            orderGoods.put("spec", goods.get("spec"));
            orderGoods.put("sku", null == goods.get("customer_sku") ? "" : goods.get("customer_sku"));
            orderGoods.put("bar_code", goods.get("vendor_bar_code"));
            orderGoods.put("golden_tax", goods.get("golden_tax"));
            orderGoods.put("unspsc", goods.get("unspsc"));
            orderGoods.put("images", Optional.ofNullable(goods.get("images")).orElse(""));
            orderGoods.put("description", goods.get("description"));
            orderGoods.put("technical", "");
            orderGoods.put("packaging", "");
            orderGoods.put("memo", "");
            orderGoods.put("unit", goods.get("unit"));
            orderGoods.put("package_unit", goods.get("package_unit"));
            orderGoods.put("package_num", goods.get("package_num"));
            orderGoods.put("warranty", "");
            orderGoods.put("delivery", goods.get("delivery"));
            orderGoods.put("length", null);
            orderGoods.put("width", null);
            orderGoods.put("height", null);
            orderGoods.put("weight", null);
            orderGoods.put("cost_center_name", costCenterName);
            orderGoods.put("demand_goods_id", null);

            orderGoods.put("num", num);

            orderGoods.put("tax_rate", goods.get("tax_rate"));
            orderGoods.put("pretax_freight", goods.get("pretax_freight"));
            orderGoods.put("tax_rate_freight", goods.get("tax_rate_freight"));
            orderGoods.put("pretax_price", goods.get("pretax_price"));

            orderGoods.put("order_customer_goods_status", OrderGoodsStatusV1Enum.NEW.name());

            orderGoods.put("goods_id", goodsId);
            orderGoods.put("cart_src", "VMI");
            orderGoods.put("delivery_time", null);
            orderGoods.put("customer_account_period", 0);
            orderGoods.put("vendor_account_period", 0);
            orderGoods.put("customer_period_time", null);
            orderGoods.put("vendor_period_time", null);
            orderGoods.put("attachment", "");
            orderGoods.put("client_order_goods_id", "");

            // 计算
            orderGoods.put("tax_payable", goods.get("tax_payable"));
            orderGoods.put("tax_payable_freight", goods.get("tax_payable_freight"));
            orderGoods.put("price", goods.get("price"));
            orderGoods.put("freight", goods.get("freight"));
            orderGoods.put("pretax_total", goods.get("pretax_total"));
            orderGoods.put("total", goods.get("total"));
            orderGoods.put("pretax_amount", goods.get("pretax_amount"));
            orderGoods.put("amount", goods.get("amount"));

            boolean existVendor = false;
            for (Map<String, Object> vendorOrder : vendorOrders) {

                if (sme.getVendorId().equals(vendorOrder.get("vendor_id"))) {

//                    if (null == vendorOrder.getGoodsList()) vendorOrder.setGoodsList(new ArrayList<>());

//                    orderGoods.setVendorOrder(vendorOrder);
                    vendorOrder.put("goodsList", Collections.singletonList(orderGoods));

                    // 计算
//                    vendorOrder.getTaxRate();
//                    vendorOrder.getTaxRateFreight();
//                    vendorOrder.getTaxPayable();
//                    vendorOrder.getTaxPayableFreight();
//                    vendorOrder.getPretaxFreight();
//                    vendorOrder.getFreight();
//                    vendorOrder.getPretaxTotal();
//                    vendorOrder.getTotal();
//                    vendorOrder.getPretaxAmount();
//                    vendorOrder.getAmount();

                    existVendor = true;
                    break;
                }
            }

            if (!existVendor) {
                Map<String, Object> vendorOrderEntityMap = new HashMap<>();

                vendorOrderEntityMap.put("vendor_id", vendorId);
                vendorOrderEntityMap.put("vendor_order_status", OrderVendorStatusEnum.UpcomingPayment.name());
                vendorOrderEntityMap.put("account_period", 0);
                vendorOrderEntityMap.put("orders_time", null);

                //供应商用户id
//                User mem = userApi.getOrganizationAdminUser(vendorId).getData();
//
//                if (null != mem) {
//                    vo.setOrdersMember(mem.getId());
//                    vo.setMemberName(mem.getFullname());
//                    vo.setUsername(mem.getUsername());
//                }
//                vendorOrderEntityMap.put("goodsList", new ArrayList<>());
//                orderGoods.setVendorOrder(vo);
                vendorOrderEntityMap.put("goodsList", Collections.singletonList(orderGoods));
//                vendorOrderEntityMap.setCustomerOrder(customerOrder);

                vendorOrders.add(vendorOrderEntityMap);
                // 计算
//                vo.getTaxRate();
//                vo.getTaxRateFreight();
//                vo.getTaxPayable();
//                vo.getTaxPayableFreight();
//                vo.getPretaxFreight();
//                vo.getFreight();
//                vo.getPretaxTotal();
//                vo.getTotal();
//                vo.getPretaxAmount();
//                vo.getAmount();
            }
        }
        customerOrder.put("account_period", 0);
        customerOrder.put("vendorOrderList", vendorOrders);

        // 计算
//        customerOrder.getTaxRate();
//        customerOrder.getTaxRateFreight();
//        customerOrder.getTaxPayable();
//        customerOrder.getTaxPayableFreight();
//        customerOrder.getPretaxFreight();
//        customerOrder.getFreight();
//        customerOrder.getPretaxTotal();
//        customerOrder.getTotal();
//        customerOrder.getPretaxAmount();
//        customerOrder.getAmount();

        return customerOrder;
    }

    /**----------------------------------------------------库存、库存单据相关逻辑------end--------------------------------------*/

    /**
     * cn/gomro/core/bizes/order/service/impl/OrdersService.uploadReceive
     * 客户上传收货单
     */
    public void uploadReceive(List<String> orderGoodsIds, List<AttachmentFormat> att, String actualDeliverTime) {

        if (CollectionUtils.isEmpty(orderGoodsIds) || CollectionUtils.isEmpty(att))
            throw new RuntimeException("参数缺失！");

        List<Map<String, Object>> orderGoodsList = getOrderCustomerGoodsByGoodsId(orderGoodsIds);

        if (null == orderGoodsList || orderGoodsList.isEmpty())
            throw new RuntimeException("商品信息不存在！");

        for (Map<String, Object> orderGoodsEntity : orderGoodsList) {
            Map<String, Object> orderGoodsParam = new HashMap<>();
            String attachment = "";
            //添加附件，如果原来没有直接添加，否则，拼接
            String oldAttachment = (String) orderGoodsEntity.get("attachment");
            if (StringUtils.isBlank(oldAttachment)) {
                attachment = JSONObject.toJSONString(att);
            } else {
                String oldAtt = JSONObject.toJSONString(att).replaceAll("\\[", "").replaceAll("\\]", "");
                attachment = "[" + oldAttachment.replaceAll("\\[", "").replaceAll("\\]", "") + "," + oldAtt + "]";
            }
            orderGoodsParam.put("attachment", JsonParseObject.parseObject(attachment, AttachmentFormat.class));
            orderGoodsParam.put("actual_deliver_time", actualDeliverTime);
            orderGoodsParam.put("id", orderGoodsEntity.get("id"));
            BoServiceUtils.updateMainBo(ModelConst.T_ORDER_CUSTOMER_GOODS, orderGoodsParam);
        }
    }

    /**
     * 修改供应商备注
     * cn/gomro/core/bizes/inquiry/service/impl/QuotationService.update
     *
     * @param customerOrderId
     * @param memo
     * @return
     */
    public Integer updateVendorMemo(String customerOrderId, String memo) {
        if (null == memo) memo = "";
        //@TODO 通过订单ID和成员ID查询对应报价商品是否只存在一条
        return JdbcTemplateUtils.builder(ModelConst.T_ORDER_VENDOR).putFieldAndVal("memo", memo)
                .eq("order_customer_id", customerOrderId).update();
    }
}
